<template>
  <div class="stacked-area-chart" :style="style">
    <KCharts
      ref="stackedAreaChartRef"
      :height="height"
      :option="option"
      v-bind="$attrs"
    />
    <div class="legend-wrapper">
      <div class="legend">
        <div v-for="(item, index) in yDataList" :key="index">
          <div
            class="legend-item"
            :class="{
              disabled: selectedObj[item.name] === false,
              hover: item.isOver,
            }"
            @mouseover="handleLegendOver(item)"
            @mouseout="handleLegendOut(item)"
            @click="handleLegendClick(item.name)"
          >
            <div class="legend-inner">
              <div class="legend-icon" :style="iconStyle(item)"></div>
              <div class="legend-label cn-regular-12">
                {{ item.name }}
              </div>
              <el-tooltip
                v-if="item.name === '付费'"
                effect="dark"
                placement="top"
                content="包含其他来源，如：火山、西瓜、站外分享等"
              >
                <img
                  v-if="item.name === '付费'"
                  class="ml-2"
                  width="12"
                  height="12"
                  src="@/assets/images/icons/question-help.png"
                  alt="说明"
                />
              </el-tooltip>
            </div>
            <div class="legend-value">
              <div class="legend-number n-regular-13">
                {{ legendNumber(item.total) }}
              </div>
              <div class="legend-unit cn-regular-12">
                {{ legendUnit(item.total) }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { createStackedAreaOption } from '@/hooks/charts/stacked-area-chart';
import type {
  Options,
  XType,
  YType,
  BaseNameDataObject
} from '@/hooks/charts/type';
import { formatDecimal } from '@/hooks/charts/util';

defineOptions({ name: 'StackedAreaChart' });

interface YData extends BaseNameDataObject {
  tooltipData?: number[];
  total: number;
}
interface YDataItem extends YData {
  isOver: boolean;
}
interface Props {
  width: string;
  height: string;
  options?: Options;
  xType: XType;
  yType: YType;
  tooltipType: YType;
  xData: number[] | string[];
  yData: YData[];
}
const props = withDefaults(defineProps<Props>(), {
  options: () => {
    return {
      showLabel: true,
      labelLimit: 0
    };
  }
});
const yDataList = ref<YDataItem[]>([]);
const option = ref({});
const stackedAreaChartRef = ref();
const selectedObj = ref<any>({});
const style = computed(() => {
  return {
    width: props.width,
    height: props.height
  };
});
const iconStyle = computed(() => {
  return (item: any) => {
    const color =
      selectedObj.value[item.name] === false ? '#dadfe9' : item.color;
    return {
      backgroundColor: color
    };
  };
});
const legendNumber = computed(() => {
  return (val: number) => {
    let number: any = val;
    if (props.yType === 'percent') {
      number = formatDecimal(number, 2);
    } else if (props.yType === 'number') {
      if (number > 10000) {
        number = parseFloat((number / 10000).toFixed(1));
      }
    }

    if (props.tooltipType !== props.yType) {
      if (props.tooltipType === 'percent') {
        number = formatDecimal(number, 2);
      } else if (props.tooltipType === 'number') {
        if (number > 10000) {
          number = parseFloat((number / 10000).toFixed(1));
        }
      }
    }

    return number;
  };
});
const legendUnit = computed(() => {
  return (val: number) => {
    let unit = '';
    if (props.yType === 'percent') {
      unit = '%';
    } else if (props.yType === 'number') {
      if (val > 10000) {
        unit = '万';
      }
    }

    if (props.tooltipType !== props.yType) {
      if (props.tooltipType === 'percent') {
        unit = '%';
      } else if (props.tooltipType === 'number') {
        if (val > 10000) {
          unit = '万';
        }
      }
    }

    return unit;
  };
});

function init() {
  yDataList.value = props.yData
    .filter((item: any) => item.total >= 0.0001)
    .map((item) => {
      if (item.name === '其他') {
        item.name = '付费';
      }
      return {
        ...item,
        isOver: false
      };
    });

  let selected = {};
  if (stackedAreaChartRef.value) {
    selected =
      stackedAreaChartRef.value.chartsRef.getOption().legend[0].selected;
  }
  option.value = createStackedAreaOption({
    selected,
    options: props.options ?? {},
    xType: props.xType,
    yType: props.yType,
    tooltipType: props.tooltipType,
    xData: props.xData,
    yData: yDataList.value.slice().reverse()
  });
}

const handleLegendClick = (name: string) => {
  // 获取当前选中的图例
  let selected: any = {};
  if (stackedAreaChartRef.value) {
    selected =
      stackedAreaChartRef.value.chartsRef.getOption().legend[0].selected;
  }

  // 对点击的图例进行取反操作
  if (Object.hasOwnProperty.call(selected, name)) {
    selected[name] = !selected[name];
  } else {
    selected[name] = false;
  }
  selectedObj.value = selected;

  // 处理最后一个图例的问题
  const selectedArr: any = [];
  for (let key in selectedObj.value) {
    if (selectedObj.value[key] === false) {
      selectedArr.push(key);
    }
  }
  if (!selected[name] && yDataList.value.length - selectedArr.length === 0) {
    selected[name] = true;
    selectedObj.value = selected;
  }

  // 修改图表配置
  stackedAreaChartRef.value.chartsRef.setOption({
    legend: {
      selected
    }
  });
};

const handleLegendOver = (item: any) => {
  item.isOver = true;

  let seriesIndex;
  const series = stackedAreaChartRef.value.chartsRef
    .getOption()
    .series.map((line: any, index: any) => {
      if (line.name === item.name) {
        line.emphasis = {
          focus: 'series'
        };
        seriesIndex = index;
      }
      return line;
    });

  stackedAreaChartRef.value.chartsRef.setOption({
    series
  });
  stackedAreaChartRef.value.chartsRef.dispatchAction({
    type: 'highlight',
    seriesIndex
  });
};

const handleLegendOut = (item: any) => {
  item.isOver = false;

  let seriesIndex;
  const series = stackedAreaChartRef.value.chartsRef
    .getOption()
    .series.map((line: any, index: any) => {
      if (line.name === item.name) {
        line.emphasis = {
          focus: 'none'
        };
        seriesIndex = index;
      }
      return line;
    });

  stackedAreaChartRef.value.chartsRef.setOption({
    series
  });
  stackedAreaChartRef.value.chartsRef.dispatchAction({
    type: 'downplay',
    seriesIndex
  });
};

watch(
  () => props.yData,
  (yData) => {
    if (!yData?.length) {
      return;
    }

    init();
  },
  { deep: true, immediate: true }
);
</script>

<style lang="scss" scoped>
.stacked-area-chart {
  position: relative;
  box-sizing: border-box;
  padding-right: 156px;

  .legend-wrapper {
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
    align-items: center;
    width: 156px;
    height: 100%;
  }

  .legend {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;

    .legend-item {
      box-sizing: border-box;
      display: flex;
      align-items: center;
      height: 28px;
      padding: 4px 6px;
      cursor: pointer;
      background: #fff;
      border: 1px solid #f2f3f5;
      border-radius: 4px;

      .legend-inner {
        display: flex;
        flex: 1;
        align-items: center;
      }

      .legend-icon {
        width: 8px;
        height: 8px;
        border-radius: 50%;
      }

      .legend-label {
        margin-left: 4px;
        color: #69718c;
      }

      .legend-value {
        display: flex;
        align-items: baseline;
      }

      .legend-number {
        color: #69718c;
      }

      .legend-unit {
        color: #69718c;
      }

      &.hover {
        background: #f7f7f8;
      }

      &.disabled {
        .legend-label {
          color: #dadfe9;
        }

        .legend-number {
          color: #dadfe9;
        }

        .legend-unit {
          color: #dadfe9;
        }
      }
    }
  }
}
</style>
